package 富婆梦.第一阶段.数值操作练习;

import java.util.Arrays;
import java.util.Random;

/**
 * 因为协议使用的基本单位都是byte
 * 所以该该类中要实现以下转换功能要求
 * 1.各种类型的主数据类型和byte的关系->使用byte数组保存各种主数据类型
 * 基本信息
 * 1 byte = 8-bit
 * 8-bit: 0000 0000
 * 需要掌握：位运算位移
 * << 操作
 * >> 操作
 * & 操作
 * | 操作
 * ^ 操作
 */
public class ByteTestTemplate {
    public static void main(String[] args) {

        // 测试各种基本数据类型与byte的关系
        //testPrimateDataFormat();
        boolean[] booleanValues = {false, true, true, false, true, true, true, true};
        byte saveToByte = boolSaveToByte(booleanValues);
        System.out.println(Integer.toBinaryString((int)saveToByte));
       /* boolean[] booleanValues = {false, true, true, false, true, true, true, true};
        // 使用一个byte保存8个boolean的状态
        byte saveToByte = boolSaveToByte(booleanValues);
        System.out.println(checkBooleanValueByIndex(saveToByte, 0));
        System.out.println(checkBooleanValueByIndex(saveToByte, 1));
        System.out.println(checkBooleanValueByIndex(saveToByte, 2));
        System.out.println(checkBooleanValueByIndex(saveToByte, 3));
        System.out.println(checkBooleanValueByIndex(saveToByte, 4));
        System.out.println(checkBooleanValueByIndex(saveToByte, 5));
        System.out.println(checkBooleanValueByIndex(saveToByte, 6));
        System.out.println(checkBooleanValueByIndex(saveToByte, 7));*/
    }


    private static void testPrimateDataFormat() {
        Random random = new Random();
        // =======================================
        // boolean 值 true 或 false。使用一个byte表示。但其实只需要其中一个bit就可以
        // 生成测试数据
        boolean[] booleanValues = {
                random.nextBoolean(), random.nextBoolean(), random.nextBoolean(), random.nextBoolean(),
                random.nextBoolean(), random.nextBoolean(), random.nextBoolean(), random.nextBoolean()
        };
        System.out.println("布尔数组：" + Arrays.toString(booleanValues));
        // 使用一个byte保存8个boolean的状态
        byte saveToByte = boolSaveToByte(booleanValues);
        System.out.println("布尔数组对应的byte：" + saveToByte);
        // 进行存储的校验
        for (int i = 0; i < booleanValues.length; i++) {
            // 判断根据索引，每个boolean都保存正常
            assert (checkBooleanValueByIndex(saveToByte, i) == booleanValues[i]);
        }


        // =======================================
        // char 类型 -》 char 使用1 个byte表示
        char s = 'f';
        byte charToByte = charToByte(s);
        System.out.println("char:" + s + " 对应的byte：" + charToByte);
        char aChar = byteToChar(charToByte);
        assert (s == aChar);

        // =======================================
        // short 值  -》short 使用2 个byte表示
        short shortV = (short)random.nextInt();
        byte[] shortBytes = shortToByteArray(shortV);
        System.out.println("shortV:" + shortV + " 对应的byte：" + Arrays.toString(shortBytes));
        short toShortV = byteArrayToShort(shortBytes);
        assert (shortV == toShortV);
//
//
//        // =======================================
//        // int 值 -》使用4 个byte表示
//        int anInt = random.nextInt();
//        byte[] intBytes = intToByteArray(anInt);
//        int toInt = byteArrayToInt(intBytes);
//        assert anInt==toInt;
//
//        // =======================================
//        // long 值 -》使用8 个byte表示
//        long aLong = random.nextLong();
//        // 用byte数组表示long
//        byte[] longBytes = longToByteArray(aLong);
//        // 读取byte数组表示的long值
//        long toLong = byteArrayToLong(longBytes);
//        // 校验正确性
//        assert (aLong == toLong);


    }


    private static byte boolSaveToByte(boolean[] booleanValue) {
        if (booleanValue.length != 8) {
            throw new RuntimeException("非法输入");
        }
        byte bits = 0;
        // 8个boolean值，正好对应byte中的8个bit，使用每个bit的1/0来表示一个正负

        // 初始byte bits = 0；也是初始化了一个byte，他的二进制表示形式为：0000 0000

        // 从右到左，为从低位到高位，即为从0到7 比如，位置0和位置3为true，其他为false，则二进制应为：0000 1001

        // 使用“或”运算，依次把为true的对应位置置为1，或运算为， a | b :a/b 任意为1，结果为1

        boolean b0 = booleanValue[0];
        if (b0) {
            // 第一个boolean值为true  这个做的其实是： 0000 0000 “或” 0000 0001 = 0000 0001
            bits = (byte) (bits | (byte) 1);
        }
        boolean b1 = booleanValue[1];
        if (b1) {
            // 第二个boolean值为true  假设上面处理第一个值为true，这个做的其实是： 0000 0001 “或” 0000 0010 = 0000 0011
            // byte： 0000 0010 为 2
            bits = (byte) (bits | (byte) 2);
        }

        boolean b2 = booleanValue[2];
        if (b2) {
            // 第三个boolean值为true  假设上面都为true，这个做的其实是： 0000 0011 “或” 0000 0100 = 0000 0111
            // byte： 0000 0100 为 4
            bits = (byte) (bits | (byte) 4);
        }

        // 后面依次类推，发现规律了吗？》
        boolean b3 = booleanValue[3];
        if (b3) {
            bits = (byte) (bits | (byte) 8);
        }


        boolean b4 = booleanValue[4];
        if (b4) {

            bits = (byte) (bits | (byte) 16);
        }

        boolean b5 = booleanValue[5];
        if (b5) {

            bits = (byte) (bits | (byte) 32);
        }

        boolean b6 = booleanValue[6];
        if (b6) {

            bits = (byte) (bits | (byte) 64);
        }

        boolean b7 = booleanValue[7];
        if (b7) {

            bits = (byte) (bits | (byte) 128);
        }

        return bits;
    }

    private static boolean checkBooleanValueByIndex(byte bits, int index) {
        if (index < 0 || index > 7) {
            throw new RuntimeException("非法输入");
        }
        // 这个就从byte确定第index个的bit是1还是0
        if (index == 0) {
            // 需要判断第1个bit，从右向左
            // 使用 & “并”  a & b:每一位a、b都为1的为1，否则为0。 比如 0010 0011 & 0000 0001 = 0000 0001
            // 这里操作为 xxxx xxxx & 0000 0001 只要xxxx xxxx 的最右边为1.则结果为1
            return (bits & 1) == 1;
        }

        if (index == 1) {
            // 需要判断第2个bit，从右向左
            // 这里操作为 xxxx xxxx & 0000 0010 只要xxxx xxxx 的最右边第二位为1.则结果为 0000 0010
            return (bits & 2) == 2;
        }

        if (index == 2) {
            // 需要判断第3个bit，从右向左
            // 这里操作为 xxxx xxxx & 0000 0100 只要xxxx xxxx 的最右边第三位为1.则结果为 0000 0100
            return (bits & 4) == 4;
        }
        // 后面自己推到，发现规律
        if (index == 3) {
            return (bits & 8) == 8;
        }

        if (index == 4) {
            return (bits & 16) == 16;
        }

        if (index == 5) {
            return (bits & 32) == 32;
        }

        if (index == 6) {
            return (bits & 64) == 64;
        }

        if (index == 7) {
            return (bits & 128) == 128;
        }

        return false;
    }

    private static byte charToByte(char value) {
        // (byte) (0 | value) 这种是无用功，因为 一个char就是一个byte
//        return (byte) (0 | value);
        return (byte) value;
    }

    private static char byteToChar(byte b) {
        return (char) b;
    }

    private static byte[] shortToByteArray(short value) {
        byte[] bytes = new byte[2];

        // 一个short 是2个byte  为0000 0000 0000 0000
        // 所以可以拆开为2 个byte ，拆开方式为位移：
        // 先去除 右边的一个byte 假设两个byte这样表示 aaaa aaaa bbbb bbbb ,先处理bbbb bbbb

        // 0xFF 是16进制数，值为 1111 1111
        byte rightByte = (byte)(value | 0xFF);//这个应该是 &

        // 这个要用到 右移操作，aaaa aaaa bbbb bbbb >> n 去掉右边N个bit
        byte leftByte  = (byte)(value >> 8);

        bytes[0] = rightByte;
        bytes[1] = leftByte;
        return bytes;
    }

    private static short byteArrayToShort(byte[] bytes) {

        // 同上，反过来
        byte rightByte = bytes[0];
        byte leftByte = bytes[1];

        int i = leftByte << 8 + rightByte;

        return (short) i;
    }

    private static byte[] intToByteArray(int value) {
        byte[] bytes = new byte[4];
        // TODO： int的byte数组表示

        return bytes;
    }

    private static int byteArrayToInt(byte[] bytes) {
        // TODO: 把4位长度的byte数组转化为对应的int值

        return 0;
    }


    private static byte[] longToByteArray(long value) {
        byte[] bytes = new byte[8];
        // TODO： 实现long值用8位长度的byte数组存储：long值其实就是8byte来表示的

        return bytes;
    }

    private static long byteArrayToLong(byte[] bytes) {
        // TODO: 把8位长度的byte数组转化为对应的long值

        return 0L;
    }

}
